package kz.pompei.porelinar.impls;

import kz.pompei.porelinar.ifaces.AtomAcceptor;
import kz.pompei.porelinar.ifaces.ErrorCode;
import kz.pompei.porelinar.ifaces.TopAtomAcceptor;
import kz.pompei.porelinar.model.Atom;
import kz.pompei.porelinar.model.AtomType;

public class AtomAnalizerImpl implements TopAtomAcceptor {
  
  private AtomAcceptor atomAcceptor;
  
  public AtomAnalizerImpl(AtomAcceptor atomAcceptor) {
    this.atomAcceptor = atomAcceptor;
  }
  
  private char[] chars;
  
  @Override
  public void start(char[] chars) {
    this.chars = chars;
    atomAcceptor.start(chars);
  }
  
  @Override
  public void newLine(int line) {
    atomAcceptor.accept(new Atom(AtomType.NL, 0, 0, line, 0));
  }
  
  enum CharType {
    UNDEFINED, SPACE, LETTER, DIGIT, ANOTHER;
  }
  
  @SuppressWarnings("unused")
  @Override
  public void accept(int offset, int length, int startLine, int startCol) {
    char firstChar = chars[offset];
    if (firstChar == '"' || firstChar == '\'') {
      atomAcceptor.accept(new Atom(AtomType.STRING, offset, length, startLine, startCol));
      return;
    }
    int len = 1;
    CharType startType = getType(firstChar);
    boolean wasPoint = false;
    FOR: for (int i = 1; i < length; i++) {
      char c = chars[offset + i];
      CharType type = getType(firstChar);
      A: {
        if (type == startType) break A;
        if (startType == CharType.SPACE) {
          atomAcceptor.accept(new Atom(AtomType.SPACES, offset + i - len, len, startLine, startCol
              + i - len));
          startType = type;
          len = 1;
          continue FOR;
        }
        if (startType == CharType.DIGIT) {
          atomAcceptor.accept(new Atom(AtomType.CONST, offset + i - len, len, startLine, startCol
              + i - len));
          startType = type;
          len = 1;
          continue FOR;
        }
        break A;
      }
      wasPoint = false;
      len++;
    }
  }
  
  private CharType getType(char c) {
    if ('0' <= c && c <= '9') return CharType.DIGIT;
    if (c == '_') return CharType.LETTER;
    if (Character.isWhitespace(c)) return CharType.SPACE;
    if (Character.isAlphabetic(c)) return CharType.LETTER;
    if (Character.isDefined(c)) return CharType.ANOTHER;
    return CharType.UNDEFINED;
  }
  
  @Override
  public void error(ErrorCode error, int offset, int length, int startLine, int startCol) {
    atomAcceptor.error(error, offset, length, startLine, startCol);
  }
  
  @Override
  public void finish() {
    atomAcceptor.finish();
  }
}
